package com.aoxiang.zbox.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.aoxiang.zbox.mapper.TodoItemMapper;
import com.aoxiang.zbox.model.dto.CreateTodoItemRequest;
import com.aoxiang.zbox.model.dto.UpdateTodoItemRequest;
import com.aoxiang.zbox.model.entity.Label;
import com.aoxiang.zbox.model.entity.TodoItem;
import com.aoxiang.zbox.model.entity.TodoSort;
import com.aoxiang.zbox.model.enums.TodoSortTypeEnum;
import com.aoxiang.zbox.model.vo.GetDeletedVO;
import com.aoxiang.zbox.model.vo.LabelTodoItemVO;
import com.aoxiang.zbox.model.vo.SimpleLabelVO;
import com.aoxiang.zbox.service.LabelService;
import com.aoxiang.zbox.service.TodoItemService;
import com.aoxiang.zbox.service.TodoSortService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Description:
 *
 * @author: aoxiang
 * @create: 2025-03-08 20:20
 **/

@Service
public class TodoItemServiceImpl extends ServiceImpl<TodoItemMapper, TodoItem> implements TodoItemService {
    @Autowired
    private TodoSortService todoSortService;
    @Autowired
    private TodoItemMapper todoItemMapper;
    @Autowired
    private LabelService labelService;

    @Override
    public void physicalDeletion(List<Long> ids) {
        todoItemMapper.physicalDeletionBatch(ids);
    }

    @Override
    public TodoItem recoverTodoItem(Long id) {
        TodoItem todoItem = todoItemMapper.selectDeleted(id);
        if (todoItem == null) {
            return null;
        }
        todoItemMapper.physicalDeletion(id);
        todoItem.setDeleted(false);
        save(todoItem);
        todoItem.getLabelList().forEach(labelId -> todoSortService.addNewTodoItemSort(todoItem.getId(), labelId, TodoSortTypeEnum.SHOW_SORT.getType()));
        return todoItem;
    }

    private void updateCompletedSort(Boolean isCompleted, Long todoItemId) {
        LambdaQueryWrapper<TodoItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TodoItem::getId, todoItemId);
        TodoItem todoItem = todoItemMapper.selectOne(queryWrapper);
        if (todoItem == null) {
            return;
        }
        if (isCompleted == todoItem.isCompleted()) {
            return;
        }
        if (isCompleted) {
            todoSortService.removeByTodoItemId(todoItemId);
            for (Long labelId : todoItem.getLabelList()) {
                if (!labelService.isCompleted(labelId)) {
                    labelService.addCompletedSort(labelId);
                }
                todoSortService.addNewTodoItemSort(todoItemId, labelId, TodoSortTypeEnum.COMPLETED_SORT.getType());
            }
        }
    }

    @Override
    public List<GetDeletedVO> getDeletedItem() {
        List<SimpleLabelVO> allSimple = labelService.getAllSimple();
        Map<Long, SimpleLabelVO> allSimpleMap;
        if (!allSimple.isEmpty()) {
            allSimpleMap = allSimple.stream().collect(Collectors.toMap(SimpleLabelVO::getId, simpleLabelVO -> simpleLabelVO));
        } else {
            allSimpleMap = new HashMap<>();
        }

        List<TodoItem> todoItems = todoItemMapper.selectDeletedList();
        return todoItems.stream().map(item -> {
            GetDeletedVO deletedVO = new GetDeletedVO();
            deletedVO.setTodoItemId(item.getId());
            deletedVO.setContent(item.getContent());
            deletedVO.setCompleted(item.isCompleted());
            deletedVO.setCreatedAt(item.getCreatedAt());
            deletedVO.setUpdatedAt(item.getUpdatedAt());
            List<Long> labelList = item.getLabelList();
            if (labelList != null && !labelList.isEmpty()) {
                List<SimpleLabelVO> simpleLabelVos = labelList.stream().map(allSimpleMap::get).collect(Collectors.toList());
                deletedVO.setLabelList(simpleLabelVos);
            } else {
                deletedVO.setLabelList(Collections.emptyList());
            }
            return deletedVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<LabelTodoItemVO> getCompletedItem() {
        return getTodoItemsBySortType(TodoSortTypeEnum.COMPLETED_SORT, true);
    }

    @Override
    public List<LabelTodoItemVO> getShownTodoItem() {
        return getTodoItemsBySortType(TodoSortTypeEnum.SHOW_SORT, false);
    }

    /**
     * 通用方法：根据排序类型获取 TodoItem
     */
    private List<LabelTodoItemVO> getTodoItemsBySortType(TodoSortTypeEnum sortTypeEnum, boolean isCompleted) {
        // 获取未删除的标签
        List<Label> labels = getLabels(sortTypeEnum);
        if (labels.isEmpty()) {
            return Collections.emptyList();
        }
        LinkedHashMap<Long, Label> labelMap = labels.stream()
                .collect(Collectors.toMap(
                        Label::getId,
                        label -> label,
                        (existing, replacement) -> existing, // 处理键冲突
                        LinkedHashMap::new // 指定使用 LinkedHashMap
                ));

        // 获取指定类型的排序列表
        List<TodoSort> todoSortList = todoSortService.list(new LambdaQueryWrapper<TodoSort>()
                .eq(TodoSort::getSortType, sortTypeEnum.getType())
                .orderByAsc(TodoSort::getShowSort));
        if (todoSortList.isEmpty()) {
            return Collections.emptyList();
        }
        Map<Long, List<TodoSort>> labelIdTodoSortListMap = todoSortList.stream()
                .collect(Collectors.groupingBy(TodoSort::getLabelId));

        // 获取所有符合条件的 TodoItem
        Map<Long, TodoItem> todoItemMap = getTodoItems(isCompleted);
        if (todoItemMap.isEmpty()) {
            return Collections.emptyList();
        }

        // 组装数据
        return assembleTodoItems(labelMap, labelIdTodoSortListMap, todoItemMap);
    }

    /**
     * 获取标签列表
     */
    private List<Label> getLabels(TodoSortTypeEnum sortTypeEnum) {
        return labelService.list(new LambdaQueryWrapper<Label>()
                .eq(Label::getIsDeleted, 0)
                .isNotNull(sortTypeEnum == TodoSortTypeEnum.SHOW_SORT ? Label::getShowSort : Label::getCompletedSort)
                .select(Label::getId, Label::getName,
                        sortTypeEnum == TodoSortTypeEnum.SHOW_SORT ? Label::getShowSort : Label::getCompletedSort)
                .orderByAsc(sortTypeEnum == TodoSortTypeEnum.SHOW_SORT ? Label::getShowSort : Label::getCompletedSort));
    }

    /**
     * 获取所有符合条件的 TodoItem
     */
    private Map<Long, TodoItem> getTodoItems(boolean isCompleted) {
        List<TodoItem> todoItemList = list(new LambdaQueryWrapper<TodoItem>().eq(TodoItem::isCompleted, isCompleted));
        return todoItemList.isEmpty() ? Collections.emptyMap()
                : todoItemList.stream().collect(Collectors.toMap(TodoItem::getId, item -> item));
    }

    /**
     * 组装 TodoItemVO 列表
     */
    private List<LabelTodoItemVO> assembleTodoItems(Map<Long, Label> labelMap,
                                                    Map<Long, List<TodoSort>> labelIdTodoSortListMap,
                                                    Map<Long, TodoItem> todoItemMap) {
        List<LabelTodoItemVO> result = new ArrayList<>();
        labelMap.forEach((labelId, label) -> {
            LabelTodoItemVO shownLabelTodoItemVO = new LabelTodoItemVO();
            shownLabelTodoItemVO.setLabelId(labelId);
            shownLabelTodoItemVO.setLabelName(label.getName());
            shownLabelTodoItemVO.setTodoItems(new ArrayList<>());
            List<TodoSort> todoSorts = labelIdTodoSortListMap.get(labelId);
            if (CollectionUtil.isEmpty(todoSorts)) {
                return;
            }
            todoSorts.forEach(todoSort -> {
                Long todoId = todoSort.getTodoId();
                TodoItem todoItem = todoItemMap.get(todoId);
                if (todoItem != null) {
                    LabelTodoItemVO.TodoItemVO todoItemVO = new LabelTodoItemVO.TodoItemVO();
                    todoItemVO.setTodoItemId(todoId);
                    todoItemVO.setContent(todoItem.getContent());
                    todoItemVO.setCreatedAt(todoItem.getCreatedAt());
                    todoItemVO.setUpdatedAt(todoItem.getUpdatedAt());
                    shownLabelTodoItemVO.getTodoItems().add(todoItemVO);
                }
            });
            result.add(shownLabelTodoItemVO);
        });
        return result;
    }

    @Override
    public void updateTodoItem(UpdateTodoItemRequest request) {
        if ((request.getLabels() == null || request.getLabels().size() == 0)
                && request.getContent() == null
                && request.getIsCompleted() == null) {
            return;
        }
        LambdaUpdateWrapper<TodoItem> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TodoItem::getId, request.getId());
        if (request.getContent() != null) {
            updateWrapper.set(TodoItem::getContent, request.getContent());
        }
        if (request.getIsCompleted() != null) {
            updateWrapper.set(TodoItem::isCompleted, request.getIsCompleted());
            updateCompletedSort(request.getIsCompleted(), request.getId());
        }
        if (request.getLabels() == null) {
            updateWrapper.set(TodoItem::getLabels, null);
            todoSortService.removeByTodoItemId(request.getId());
        } else {
            LambdaQueryWrapper<TodoSort> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(TodoSort::getTodoId, request.getId());
            List<TodoSort> todoSorts = todoSortService.list(queryWrapper);
            ArrayList<Long> updateLabels = new ArrayList<>(request.getLabels());
            for (TodoSort todoSort : todoSorts) {
                if (!request.getLabels().contains(todoSort.getLabelId())) {
                    todoSortService.removeByTodoItemIdAndLabelId(request.getId(), todoSort.getLabelId(), TodoSortTypeEnum.SHOW_SORT.getType());
                } else {
                    updateLabels.remove(todoSort.getLabelId());
                }
            }
            updateLabels.forEach(labelId -> todoSortService.addNewTodoItemSort(request.getId(), labelId, getTodoSortType(request.getIsCompleted())));
        }
        todoItemMapper.update(null, updateWrapper);
    }

    private Integer getTodoSortType(Boolean isCompleted) {
        if (isCompleted) {
            return TodoSortTypeEnum.COMPLETED_SORT.getType();
        } else {
            return TodoSortTypeEnum.SHOW_SORT.getType();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTodoItem(Long id) {
        removeById(id);
        todoSortService.removeByTodoItemId(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createTodoItem(CreateTodoItemRequest request) {
        TodoItem todoItem = new TodoItem();
        todoItem.setContent(request.getContent());
        todoItem.setLabelList(request.getLabels());
        todoItem.setCompleted(false);
        todoItem.setDeleted(false);
        save(todoItem);

        request.getLabels().forEach(labelId -> todoSortService.addNewTodoItemSort(todoItem.getId(), labelId, TodoSortTypeEnum.SHOW_SORT.getType()));
        return todoItem.getId();
    }
}
